/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       image.cpp
 * Author:     karooolek
 * Created on: 2009-03-22
 *
 **********************************************************************************************************************/

#include "image.h"

namespace mGameEngine
{
namespace Graphics
{

Image::Image() :
    _data(NULL), _width(0), _height(0), _bpp(0)
{
}

Image::Image(const uint8 *data, uint width, uint height, uint8 bpp) :
    _data(NULL)
{
    setData(data, width, height, bpp);
}

Image::~Image()
{
    if(_data)
    {
        delete[] _data;
    }
}

void Image::setData(const uint8 *data, uint width, uint height, uint8 bpp)
{
    // free previous data
    if(_data)
    {
        delete[] _data;
    }

    // set new data
    _width = width;
    _height = height;
    _bpp = bpp;
    uint size = _width * _height * _bpp / 8;
    _data = new uint8[size];
    memcpy(_data, data, size);
}

Color Image::getColorAt(uint x, uint y) const
{
    // pixel outside image
    if(!_data || x >= _width || y >= _height)
    {
        return Color();
    }

    const uint8 *data = _data + (x + _width * y) * _bpp / 8;
    
    switch(_bpp)
    {
    // 8bpp - grayscale
    case 8:
        return Color(data[0], data[0], data[0]);

    // TODO 16bpp - grayscale
    case 16:
        return Color(float(*(uint16 *)data) / 65535.0f,
                    float(*(uint16 *)data) / 65535.0f,
                    float(*(uint16 *)data) / 65535.0f);

    // 24bpp - RGB
    case 24:
        return Color(data[0], data[1], data[2]);

    // 32bpp - RGBA
    case 32:
        return Color(data[0], data[1], data[2],  data[3]);

    // unsupported bitrate
    default:
        return Color();
    }
}

void Image::setColorAt(const Color &color, uint x, uint y)
{    
    // pixel outside image
    if(!_data || x >= _width || y >= _height)
    {
        return;
    }

    uint8 *ptr = _data + (x + _width * y) * _bpp / 8;
    uint16 gray = uint16(65535.0f * 0.333333f * (color.r + color.g + color.b));

    switch(_bpp)
    {

    // 8bpp - grayscale
    case 8:
        ptr[0] = gray >> 8 & 0xff;
        return;

    // 16bpp - grayscale
    case 16:
        ptr[0] = gray >> 8 & 0xff;
        ptr[1] = gray & 0xff;
        return;

    // 24bpp - RGB
    case 24:
        ptr[0] = uint8(255.0f * color.r);
        ptr[1] = uint8(255.0f * color.g);
        ptr[2] = uint8(255.0f * color.b);
        break;
    
    // 32bpp - RGBA
    case 32:
        ptr[0] = uint8(255.0f * color.r);
        ptr[1] = uint8(255.0f * color.g);
        ptr[2] = uint8(255.0f * color.b);
        ptr[3] = uint8(255.0f * color.a);
        break;

    // unsupported bitrate
    default:
        break;
    }
}

const uint8 *Image::getDataAt(uint x, uint y) const
{
    // pixel outside image
    if(!_data || x >= _width || y >= _height)
    {
        return NULL;
    }

    // return pixel value
    return _data + (x + _width * y) * _bpp / 8;
}

void Image::setDataAt(const uint8 *data, uint x, uint y)
{
    // pixel outside image
    if(!data || !_data || x >= _width || y >= _height)
    {
        return;
    }

    // set pixel data
    uint8 *ptr = _data + (x + _width * y) * _bpp / 8;
    memcpy(ptr, data, _bpp / 8);
}

}
}

